/*
    模拟停车场的运行（生产者、消费者模型）
    停车位    多入口    多出口
    临界资源是车位，生产者为入口，消费者为出口
*/

#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <string.h>

#define park_num 50
#define entry_num 2
#define out_num 2
#define car_num 100

int running = 1;

typedef struct
{
    pthread_cond_t no_full, no_empty;
    pthread_mutex_t mut;
    int spots[park_num][2];    //标记是否被占用
    int size;
}parking;

parking park;

void* entrance(void* avg);
void* out_thread(void* avg);

int main()
{
    //随机数种子
    srand(time(NULL));

    // 初始化结构体
    pthread_cond_init(&park.no_empty, NULL);
    pthread_cond_init(&park.no_full, NULL);
    pthread_mutex_init(&park.mut, NULL);
    //模拟入口
    int entry[entry_num] = {0, 1};
    pthread_t entry_tid[entry_num];
    for(int i = 0; i < entry_num; i++)
    {
        pthread_create(&entry_tid[i], NULL, entrance, &entry[i]);
    }

    //创建出口线程
    int exit[out_num] = {0, 1};
    pthread_t exit_tid[out_num];
    for(int i = 0; i < out_num; i++)
    {
        pthread_create(&exit_tid[i], NULL, out_thread, &exit[i]);
    }

    // 等待所有线程完成（这里我们不退出，所以用 sleep 模拟）
    sleep(5); // 给线程足够时间处理车辆

    // join 所有线程
    for(int i = 0; i < out_num; i++)
    {
        pthread_join(exit_tid[i], NULL);
    }
    for(int i = 0; i < entry_num; i++)
    {
        pthread_join(entry_tid[i], NULL);
    }

    // 销毁资源
    pthread_mutex_destroy(&park.mut);

    return 0;
}

// 入口线程执行
void* entrance(void* avg)
{
    int eid = *(int*)avg;
    //模拟汽车随机到达入口
    for(int i = 0; i < car_num/2; i++)
    {
        int car_id = rand()%100;      //随机生成id
        pthread_mutex_lock(&park.mut);
        while(park.size == park_num)
        {
            //没有车位等待
            printf("没有空余车位，请耐心等待！\n");
            pthread_cond_wait(&park.no_full, &park.mut);
        }
        //有车位了，开始停车
        park.size++;
        //找一个空位
        int i = 0;
        for(i = 0; i < park_num; i++)
        {
            if(park.spots[i][0] == 0)
            {
                park.spots[i][0] = 1;
                park.spots[i][1] = car_id;
                break;
            }
        }
        printf("汽车 %d 从入口 %d 进入停车场，停在了 %d 号车位！\n", car_id, eid, i);
        //唤醒
        pthread_cond_signal(&park.no_empty);
        pthread_mutex_unlock(&park.mut);
        usleep(500000); // 增加延时，模拟车辆到达间隔 0.5 秒
    }
}

//出口函数执行
void* out_thread(void* avg)
{
    int out_id = *(int*)avg;
    for(int i = 0; i < car_num/2; i++)
    {
        pthread_mutex_lock(&park.mut);
        while(park.size == 0)
        {
            //停车场内没有汽车
            printf("此时没有汽车在停车场中！\n");
            pthread_cond_wait(&park.no_empty, &park.mut);
        }
        //有汽车了，可以出去
        park.size--;
        //找一个空位
        int i = 0;
        for(i = 0; i < park_num; i++)
        {
            if(park.spots[i][0] == 1)
            {
                park.spots[i][0] = 0;
                break;
            }
        }
        printf("汽车 %d 从出口 %d 驶出停车场，停车场中还有%d 辆车！\n", park.spots[i][1], out_id, park.size);
        //唤醒
        pthread_cond_signal(&park.no_full);
        pthread_mutex_unlock(&park.mut);
        sleep(1); // 增加延时，模拟车辆到达间隔 0.2 秒
    }
    return NULL;
}